﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Reflection;
using System.Reflection.Emit;
using System.Diagnostics;

namespace Cs2as.ScanAssembly
{
    public static class Scan
    {
        public static void Go(string assemblyPath)
        {
            Console.WriteLine("Scanning " + assemblyPath + " for potential issues...");
            Console.WriteLine(@"
Please note: Scanning is not designed to find all issues that can arise when 
converting your code.  Scanning only looks for a few specific types of issues 
that are difficult to detect otherwise.  Please see the codeplex site for a 
full explanation of what scanning is used for.
");

            var a = Assembly.LoadFile(assemblyPath);
            Globals.LoadOpCodes();

            foreach (var type in a.GetTypes())
            {
                foreach (var method in type.GetMethods(BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Static | BindingFlags.Instance | BindingFlags.Static))
                {
                    var reader = new MethodBodyReader(method);

                    if (reader.instructions == null)
                        continue;

                    foreach (var il in reader.instructions.Where(o => o.Operand != null && o.Code.OperandType == OperandType.InlineMethod))
                    {
                        var call = (MethodBase)il.Operand;
                        var name = call.DeclaringType.FullName;

                        Func<string> foundAt = () => "Found at " + method.DeclaringType.FullName + "." + method.Name;// +":" + call.ToString();

                        if (name.StartsWith("System.Collections.Generic.Dictionary"))
                        {
                            if (call.Name == "get_Item")
                                Console.WriteLine("Warning: Dictionary indexer found.  Use .GetValue() instead. " + foundAt());
                            else if (!name.Contains("+KeyCollection[") && !name.Contains("+ValueCollection[") && call.Name == "GetEnumerator")
                                Console.WriteLine("Warning: Dictionary being enumerated on.  Use .KeyValues() instead. " + foundAt());
                        }
                        else if (name.StartsWith("System.Collections.Generic.HashSet"))
                        {
                            if (call.Name == "GetEnumerator")
                                Console.WriteLine("Warning: HashSet being enumerated on.  Use .Values() instead.  " + foundAt());
                        }

                        foreach (var parameter in call.GetParameters())
                        {
                            if (parameter.ParameterType.FullName.StartsWith("System.Collections.Generic.IEnumerable"))
                            {
                                if (call.IsGenericMethod && call.GetGenericArguments().Any(o => o.FullName.StartsWith("System.Collections.Generic.KeyValuePair")))
                                    Console.WriteLine("Warning: Dictionary might be being used as an IEnumerable.  " + foundAt());
                            }
                        }
                    }
                }
            }

            Console.WriteLine("\nScanning complete.");
        }
    }
}
